package cn.dduan.fool.design.pattern.behavior.state;

/**
 * 状态模式
 * <p>
 * 定义：
 * 1、当对象的行为取决于它的属性时，我们称这些属性为状态，那该对象就称为状态对象。
 * 2、对于状态对象而言，它的行为依赖于它的状态
 * <p>
 * 优点：
 * 1、封装了转换规则，允许状态转换逻辑与状态对象合成一体，而不是某一个巨大的条件语句块
 * 2、将所有与状态有关的行为放到一个类中，可以方便地增加新的状态，只需要改变对象状态即可改变对象的行为
 * <p>
 * 缺点：
 * 1、需要在枚举状态之前需要确定状态种类
 * 2、会导致增加系统类和对象的个数
 * 3、对 “开闭原则” 的支持并不友好，新增状态类需要修改那些负责状态转换的源代码，否则无法切换到新增状态；而且修改某个状态类的行为也需修改对应类的源代码
 * <p>
 * 使用场景：
 * 1、代码中包含大量与对象状态有关的条件语句，以及对象的行为依赖于它的状态，并且可以根据它的状态改变而改变它的相关行为
 * <p>
 * 策略模式和状态模式比较：
 * 1、策略模式和状态模式的结构几乎完全一致，但是它们的目的和本质完全不一样
 * 2、策略模式是围绕可以互换的算法来创建业务的，而状态模式是通过改变对象内部的状态来帮助对象控制自己行为的
 * 3、前者行为是彼此独立、可以相互替换的，后者行为是不可以相互替换的
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
public class StatePattern {
    public static void main(String[] args) {
        // 有3间房
        Room[] rooms = new Room[2];
        // 初始化
        for (int i = 0; i < rooms.length; i++) {
            rooms[i] = new Room();
        }
        System.out.println("有空房：" + (rooms.length + 1));
        // 第一间房
        // 预订
        rooms[0].bookRoom();
        // 入住
        rooms[0].checkInRoom();
        // 预订
        rooms[0].bookRoom();
        System.out.println(rooms[0]);
        System.out.println("---------------------------");

        //第二间房
        rooms[1].checkInRoom();
        rooms[1].bookRoom();
        rooms[1].checkOutRoom();
        rooms[1].bookRoom();
        System.out.println(rooms[1]);
    }
}

/**
 * 状态接口
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
interface State {
    /**
     * @desc 预订房间
     */
    public void bookRoom();

    /**
     * @desc 退订房间
     */
    public void unsubscribeRoom();

    /**
     * @desc 入住
     */
    public void checkInRoom();

    /**
     * @desc 退房
     */
    public void checkOutRoom();

}

/**
 * 房间类
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class Room {
    /**
     * 房间的三个状态
     */
    // 空闲状态
    State freeTimeState;
    // 入住状态
    State checkInState;
    // 预订状态
    State bookedState;

    State state;

    public Room() {
        freeTimeState = new FreeTimeState(this);
        checkInState = new CheckInState(this);
        bookedState = new BookedState(this);

        //初始状态为空闲
        state = freeTimeState;
    }

    /**
     * @desc 预订房间
     */
    public void bookRoom() {
        state.bookRoom();
    }

    /**
     * @desc 退订房间
     */
    public void unsubscribeRoom() {
        state.unsubscribeRoom();
    }

    /**
     * @desc 入住
     */
    public void checkInRoom() {
        state.checkInRoom();
    }

    /**
     * @desc 退房
     */
    public void checkOutRoom() {
        state.checkOutRoom();
    }

    @Override
    public String toString() {
        return "该房间的状态是:" + getState().getClass().getName();
    }

    /**
     * getter和setter方法
     */
    public State getFreeTimeState() {
        return freeTimeState;
    }

    public void setFreeTimeState(State freeTimeState) {
        this.freeTimeState = freeTimeState;
    }

    public State getCheckInState() {
        return checkInState;
    }

    public void setCheckInState(State checkInState) {
        this.checkInState = checkInState;
    }

    public State getBookedState() {
        return bookedState;
    }

    public void setBookedState(State bookedState) {
        this.bookedState = bookedState;
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }
}

/**
 * 空闲状态只能预订和入住
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class FreeTimeState implements State {

    Room hotelManagement;

    public FreeTimeState(Room hotelManagement) {
        this.hotelManagement = hotelManagement;
    }


    @Override
    public void bookRoom() {
        System.out.println("您已经成功预订了...");
        //状态变成已经预订
        hotelManagement.setState(hotelManagement.getBookedState());
    }

    @Override
    public void checkInRoom() {
        System.out.println("您已经成功入住了...");
        //状态变成已经入住
        hotelManagement.setState(hotelManagement.getCheckInState());
    }

    @Override
    public void checkOutRoom() {
        //不需要做操作
    }

    @Override
    public void unsubscribeRoom() {
        //不需要做操作
    }
}

/**
 * 入住状态房间只能退房
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class BookedState implements State {
    Room hotelManagement;

    public BookedState(Room hotelManagement) {
        this.hotelManagement = hotelManagement;
    }

    @Override
    public void bookRoom() {
        System.out.println("该房间已近给预定了...");
    }

    @Override
    public void checkInRoom() {
        System.out.println("入住成功...");
        //状态变成入住
        hotelManagement.setState(hotelManagement.getCheckInState());
    }

    @Override
    public void checkOutRoom() {
        //不需要做操作
    }

    @Override
    public void unsubscribeRoom() {
        System.out.println("退订成功,欢迎下次光临...");
        //变成空闲状态
        hotelManagement.setState(hotelManagement.getFreeTimeState());
    }
}

/**
 * 入住可以退房
 *
 * @author dduan
 * @version 1.0
 * @date 2023/4/10
 */
class CheckInState implements State {
    Room hotelManagement;

    public CheckInState(Room hotelManagement) {
        this.hotelManagement = hotelManagement;
    }

    @Override
    public void bookRoom() {
        System.out.println("该房间已经入住了...");
    }

    @Override
    public void checkInRoom() {
        System.out.println("该房间已经入住了...");
    }

    @Override
    public void checkOutRoom() {
        System.out.println("退房成功....");
        //状态变成空闲
        hotelManagement.setState(hotelManagement.getFreeTimeState());
    }

    @Override
    public void unsubscribeRoom() {
        //不需要做操作
    }
}